
// MainFrm.cpp : implementation of the CMainFrame class
//

#include "stdafx.h"
#include <algorithm>
#include "Bloodlead.h"

#include "MainFrm.h"
#include "DisplayView.h"
#include "ReportView.h"
#include "DisplayView.h"
#include "BloodleadDoc.h"
#include "LogView.h"

#include "SettingDlg.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

// CMainFrame

IMPLEMENT_DYNCREATE(CMainFrame, CFrameWnd)

BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
	ON_WM_CREATE()
	ON_COMMAND_RANGE(ID_COM1, ID_COM1+32, &CMainFrame::OnComSetting)
	ON_COMMAND(ID_OPERATOR_ADJUEST, &CMainFrame::OnOperatorAdjuest)
	ON_COMMAND(ID_OPERATOR_SAMPLING, &CMainFrame::OnOperatorSampling)
	ON_MESSAGE( ON_COM_RECEIVE, &CMainFrame::OnComReceive)
	ON_WM_TIMER()
END_MESSAGE_MAP()

static UINT indicators[] =
{
	ID_SEPARATOR,           // status line indicator
	ID_INDICATOR_CAPS,
	ID_INDICATOR_NUM,
	ID_INDICATOR_SCRL,
};

// CMainFrame construction/destruction
void OnReceive()
{
	CWinApp* pApp = AfxGetApp();
	
	CWnd* pMainWnd = pApp->GetMainWnd();
	if( pMainWnd )
		pMainWnd->PostMessage( ON_COM_RECEIVE );
}

CMainFrame::CMainFrame()
{
	// TODO: add member initialization code here
	m_nSamplingSeconds = 0;
	m_nCount = 0;
	memset( m_ComPortInfoVec, 0, sizeof(m_ComPortInfoVec) );
	memset( m_CommConfig, 0, sizeof(m_CommConfig) );
}

CMainFrame::~CMainFrame()
{
}

int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
	if (CFrameWnd::OnCreate(lpCreateStruct) == -1)
		return -1;

	if (!m_wndStatusBar.Create(this))
	{
		TRACE0("Failed to create status bar\n");
		return -1;      // fail to create
	}
	m_wndStatusBar.SetIndicators(indicators, sizeof(indicators)/sizeof(UINT));

	vector< SSerInfo > asi;
	EnumSerialPorts( asi );

	m_nCount = asi.size();

	for( int i = 0; i < min( _countof(m_ComPortInfoVec), asi.size() ); ++i )
	{
		m_ComPortInfoVec[i] = asi.at(i);
		BuildCommDCB( _T("9600, 8, n, 1"), &m_CommConfig[i].dcb );
	}

	CMenu* pMenu = GetMenu();
	if( pMenu )
	{
		CMenu* pOptionMenu = pMenu->GetSubMenu(0);
		if( pOptionMenu )
		{
			SettingMenu.CreateMenu();
			for( size_t i = 0; i < asi.size(); ++i )
			{
				TCHAR szMenu[256];
				_sntprintf( szMenu, _countof(szMenu), _T("%s"), m_ComPortInfoVec[i].strFriendlyName.c_str() );
				SettingMenu.AppendMenu( MF_STRING, ID_COM1+i, szMenu );
			}

			pOptionMenu->InsertMenu( 0, MF_BYPOSITION|MF_POPUP|MF_STRING, (UINT)SettingMenu.GetSafeHmenu(), _T("Setting") );
		}
	}

	DrawMenuBar();

	m_Comm.OnReceive = OnReceive;
	return 0;
}

BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT /*lpcs*/,
	CCreateContext* pContext)
{
	// create splitter window
	if (!m_wndSplitter.CreateStatic(this, 3, 1))
		return FALSE;

	if (!m_wndSplitter.CreateView(0, 0, RUNTIME_CLASS(CReportView), CSize(100, 300), pContext) ||
		!m_wndSplitter.CreateView(1, 0, RUNTIME_CLASS(CDisplayView), CSize(100, 200), pContext) ||
		!m_wndSplitter.CreateView(2, 0, RUNTIME_CLASS(CLogView), CSize(100, 200), pContext))
	{
		m_wndSplitter.DestroyWindow();
		return FALSE;
	}

	return TRUE;
}

BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
{
	if( !CFrameWnd::PreCreateWindow(cs) )
		return FALSE;
	// TODO: Modify the Window class or styles here by modifying
	//  the CREATESTRUCT cs

	return TRUE;
}

// CMainFrame diagnostics

#ifdef _DEBUG
void CMainFrame::AssertValid() const
{
	CFrameWnd::AssertValid();
}

void CMainFrame::Dump(CDumpContext& dc) const
{
	CFrameWnd::Dump(dc);
}
#endif //_DEBUG


// CMainFrame message handlers

CReportView* CMainFrame::GetTopPane()
{
	CWnd* pWnd = m_wndSplitter.GetPane(0, 0);
	CReportView* pView = DYNAMIC_DOWNCAST(CReportView, pWnd);
	return pView;
}

CDisplayView* CMainFrame::GetMiddlePane()
{
	CWnd* pWnd = m_wndSplitter.GetPane(1, 0);
	CDisplayView* pView = DYNAMIC_DOWNCAST(CDisplayView, pWnd);
	return pView;
}

void CMainFrame::OnComSetting( UINT nID )
{
	// TODO: Add your command handler code here
	int nIndex = nID - ID_COM1;
	m_CommConfig[nIndex].dwSize = sizeof( COMMCONFIG );
	BOOL bRet = ::CommConfigDialog( m_ComPortInfoVec[nIndex].strPortName.c_str(), NULL, &m_CommConfig[nIndex] );
	if( FALSE == bRet )
	{
		LPVOID lpMsgBuf;
		DWORD dw = GetLastError(); 

		FormatMessage(
			FORMAT_MESSAGE_ALLOCATE_BUFFER | 
			FORMAT_MESSAGE_FROM_SYSTEM |
			FORMAT_MESSAGE_IGNORE_INSERTS,
			NULL,
			dw,
			MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
			(LPTSTR) &lpMsgBuf,
			0, NULL );

		LocalFree( lpMsgBuf );

		memset( &m_CommConfig[nIndex], 0, sizeof(COMMCONFIG) );
	}
}

void CMainFrame::OnOperatorAdjuest()
{
	// TODO: Add your command handler code here
	XGC_WRITELOG( LOG, _T("adjuest start...") );
	mInputVec.clear();

	mOperator = enAdjuest;
	CBloodleadDoc* pDoc = GetTopPane()->GetDocument();

	CListCtrl& listCtrl = GetTopPane()->GetListCtrl();
	INT_PTR nRet = AfxMessageBox( _T("do you want clear all data?"), MB_YESNO );
	if( nRet == IDYES )
	{
		listCtrl.DeleteAllItems();
		pDoc->ClearAll();
	}

	CEnterDlg dlg;
	do
	{
		nRet = dlg.DoModal();
		if( nRet == IDOK )
		{
			TCHAR szValue[256];
			_sntprintf( szValue, _countof(szValue), _T("%5.4lf"), dlg.MfValue() );
			INT nItem = listCtrl.InsertItem( listCtrl.GetItemCount(),  _T("") );
			if( nItem >= 0 )
			{
				listCtrl.SetItemText( nItem, 1, szValue );
			}
			pDoc->AppendRecordset( 0.0f, dlg.MfValue() );
		}
	}while( nRet == IDOK );

	pDoc->Index(0);
	nRet = AfxMessageBox( _T("do you want begin adjust now?"), MB_YESNO );
	if( nRet == IDYES )
	{
		BeginSampling();
	}
}

void CMainFrame::BeginSampling()
{
	CSettingDlg dlg( m_ComPortInfoVec, m_CommConfig, m_nCount );
	if( IDOK == dlg.DoModal() )
	{
		CBloodleadDoc* pDoc = GetTopPane()->GetDocument();
		if( !pDoc )
			return;

		pDoc->SaveSetting( dlg.InvaintSeconds(), dlg.SamplingSeconds() );
		struct Operator
		{
			Operator( CBloodleadDoc& doc )
				: mDoc( doc )
			{
			}

			CBloodleadDoc& mDoc;
			void operator()( double fValue )
			{
				mDoc.AppendRecordset( 0.0f, fValue );
			}
		};

		std::for_each( mInputVec.begin(), mInputVec.end(), Operator( *pDoc ) );
		m_ReciveBuffer.clear();

		m_BeginTime = CTime::GetCurrentTime();
		SetTimer( 0, (UINT)dlg.SamplingSeconds()*1000, NULL );
		SetTimer( 1, (UINT)dlg.InvaintSeconds()*1000, NULL );

		INT nIndex = dlg.Index();

		m_Comm.OpenCommPort( m_ComPortInfoVec[nIndex].strDevPath.c_str() );
		m_Comm.SetupPort();
		m_Comm.SetState( &m_CommConfig[nIndex].dcb );

		m_Comm.Write( "\x61", 1 );
		mCmdState = eCmd_Sampling_Begin;
	}
}

size_t CMainFrame::FindReadyPosition() 
{
	const char flag[] = "\x5f\x5f\x5f\x5f\x5f\x20";
	const char *cur = flag;
	for( size_t i = 0; i < m_ReciveBuffer.size(); ++i, ++cur )
	{
		if( *cur == 0x20 )
		{
			return i;
		}

		if( m_ReciveBuffer[i] != *cur )
			cur = flag;
	}

	return -1;
}

void CMainFrame::OnOperatorSampling()
{
	// TODO: Add your command handler code here
	CListCtrl& listCtrl = GetTopPane()->GetListCtrl();
	listCtrl.DeleteAllItems();
	mOperator = enSampling;
	BeginSampling();
}

LRESULT CMainFrame::OnComReceive( WPARAM wParam, LPARAM lParam )
{
	CHAR szBuffer[256];
	INT nRead = m_Comm.Read( szBuffer, sizeof(szBuffer), 10 );

	if( nRead < 0 )
		return 0;

	switch( mCmdState )
	{
	case eCmd_Sampling_Begin:
		m_ReciveBuffer.insert( m_ReciveBuffer.end(), szBuffer, szBuffer + nRead );
		m_Comm.ClearInputBuffer();

		if( m_ReciveBuffer.size() >= 6 )
		{
			mCmdState = eCmd_Sampling_Ready;
		}
		break;
	case eCmd_Sampling_Ready:
		if( FindReadyPosition() != -1 )
		{
			mCmdState = eCmd_Sampling_Read;
		}
		break;
	case eCmd_Sampling_Read:
		m_ReciveBuffer.insert( m_ReciveBuffer.end(), szBuffer, szBuffer + nRead );
		m_Comm.ClearInputBuffer();

		break;
	case eCmd_Sampling_Process:
		break;
	}

	return 0;
}

void CMainFrame::AnalyseSamplingData()
{
	size_t nPos = FindReadyPosition() + 1;

	CBloodleadDoc* pDoc = GetMiddlePane()->GetDocument();
	if( !pDoc )
		return;

	UINT nElc = 0;
	if( nPos != -1 )
	{
		for( size_t nPosition = nPos; nPosition < m_ReciveBuffer.size(); ++nPosition )
		{
			if( m_ReciveBuffer[nPosition] == 0x20 )
			{
				pDoc->AppendElcValue( nElc );
				nElc = 0;
				continue;
			}

			nElc <<= 4;
			nElc |= (m_ReciveBuffer[nPosition]&0x0f);
		}
	}
}

void CMainFrame::OnTimer(UINT_PTR nIDEvent)
{
	// TODO: Add your message handler code here and/or call default
	if( nIDEvent == 0 )
	{
		KillTimer(0);
		KillTimer(1);

		mCmdState = eCmd_Sampling_Process;
		// m_Comm.Close();
		AnalyseSamplingData();

		//KillTimer(0);
		//KillTimer(1);
		
		GetMiddlePane()->Refresh();
		GetMiddlePane()->Invalidate(FALSE);
		GetMiddlePane()->SendMessage( WM_USER + 10000, (WPARAM)mOperator );

		CBloodleadDoc* pDoc = GetMiddlePane()->GetDocument();

		mCmdState = eCmd_None;
	}
	else if( nIDEvent == 1 )
	{
		m_Comm.Write( "\x61", 1 );
	}

	CFrameWnd::OnTimer(nIDEvent);
}

void CMainFrame::NextSampling()
{
	CBloodleadDoc* pDoc = GetMiddlePane()->GetDocument();
	if( !pDoc->Index( pDoc->Index() + 1 ) )
	{
		m_Comm.Close();
		if( mOperator == enAdjuest )
		{
			CString str;
			str.Format( _T(" R = %f, B0 = %f, B1 = %f " ), pDoc->CalculateR(), pDoc->GetB0(), pDoc->GetB1() );
		}
		else
		{
		}
		return;
	}

	m_ReciveBuffer.clear();
	m_BeginTime = CTime::GetCurrentTime();
	SetTimer( 0, UINT( pDoc->SamplingSeconds()*1000 ), NULL );
	SetTimer( 1, UINT( pDoc->InventSeconds()*1000 ), NULL );

	pDoc->ClearElc();
	m_Comm.Write( "\x61", 1 );
	mCmdState = eCmd_Sampling_Begin;
}